#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <omp.h>

#define run_times 10
#define test_times 100000
#define test_times_1 10
#define MAX_PROCESSORS 8
#define MAX_MACHINES 32

double times[MAX_MACHINES][run_times];
FILE *fp;
void output(struct rusage* usage);

int test_omp(int run, int nump, void (*init)(int), void (*barrier)(void))
{
    int i, t;
    init(nump);

#pragma omp parallel num_threads(nump) private(t)
    {
        t = 0;
        long begin = clock();
        while (t++ < test_times) {
            barrier();
        }
        long finish = clock();
        times[nump][run] = (double)(finish - begin) / CLOCKS_PER_SEC / test_times;
    }

    return 0;
}

void init_omp(char *filename)
{
    fp = fopen(filename, "w");
    if (fp == NULL) {
        printf("Can't open input file %s\n", filename);
        exit(1);
    }
    memset(times, 0, sizeof(times));
}

void run_omp(void (*init)(int), void (*barrier)(void))
{
    int i, j;
    for (j=2; j<=MAX_PROCESSORS; ++j) {
        for (i=0; i<run_times; ++i)
            test_omp(i, j, init, barrier);
    }
}

void printout(int top)
{
    int i, j;
    for (i=2; i<=top; ++i) {
        double average = 0.0;
        for (j=0; j<run_times; ++j) average += times[i][j];
        average /= run_times;
        fprintf(fp, "num_of_threads\n%d\navearge:\n%.10lf\n", i, average);
    }

    struct rusage usage;
    getrusage(RUSAGE_SELF, &usage);
    output(&usage);
}

void output(struct rusage* usage)
{
    fprintf(fp, "user time used:\n%ld.06%ld\n", usage->ru_utime.tv_sec, usage->ru_utime.tv_usec);
    fprintf(fp, "system time used:\n%ld.%ld\n", usage->ru_stime.tv_sec, usage->ru_stime.tv_usec);
    fprintf(fp, "maximum resident set size:\n%ld\n", usage->ru_maxrss);
    fprintf(fp, "integral shared memory size:\n%ld\n", usage->ru_ixrss);
    fprintf(fp, "integral unshared data size:\n%ld\n", usage->ru_idrss);
    fprintf(fp, "integral unshared stack size:\n%ld\n", usage->ru_isrss);
    fprintf(fp, "page reclaims:\n%ld\n", usage->ru_minflt);
    fprintf(fp, "page faults:\n%ld\n", usage->ru_majflt);
    fprintf(fp, "swaps:\n%ld\n", usage->ru_nswap);
    fprintf(fp, "block input operations:\n%ld\n", usage->ru_inblock);
    fprintf(fp, "block output operations:\n%ld\n", usage->ru_oublock);
    fprintf(fp, "message sent:\n%ld\n", usage->ru_msgsnd);
    fprintf(fp, "message received:\n%ld\n", usage->ru_msgrcv);
    fprintf(fp, "signals received:\n%ld\n", usage->ru_nsignals);
    fprintf(fp, "voluntary context switches:\n%ld\n", usage->ru_nvcsw);
    fprintf(fp, "involuntary context switches:\n%ld\n", usage->ru_nivcsw);
}

